home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / recov / recovery.c < prev    next >
C/C++ Source or Header  |  1990-10-11  |  57KB  |  2,012 lines

  1. /* 
  2.  * recovery.c --
  3.  *
  4.  *    The routines here maintain up/down state about other hosts.
  5.  *    Other modules register as clients of the recovery module,
  6.  *    and can then ask to be called back when some other host crashes
  7.  *    or reboots.  Modules always get called back when someone crashes,
  8.  *    and then they have the option of being called back when the
  9.  *    host reboots.  Regular message traffic plus explicit pinging
  10.  *    are used to track the state of the other hosts.  Pinging is
  11.  *    only done if some module is explicitly interested in a host.
  12.  *
  13.  *    Recov_HostAlive and Recov_HostDead are used by RPC to tell us when
  14.  *    a messages have arrived, or if transactions have timed out.
  15.  *    Recov_IsHostDown is used to query the state of another host,
  16.  *    Recov_RebootCallBack is used to get a callback upon a reboot, and
  17.  *    Recov_WaitForHost is used to block a process until a host reboots.
  18.  *    (Recov_WaitForHost isn't used much.  Instead, modules rely on the
  19.  *    recovery callbacks to indicate that a host is back to life, and
  20.  *    they block processes in their own way.)
  21.  *
  22.  *    Note: A synchronization hook is provided by Recov_HostAlive;  its
  23.  *    caller can be blocked if crash recovery actions are in progress.
  24.  *
  25.  * Copyright 1987 Regents of the University of California
  26.  * All rights reserved.
  27.  */
  28.  
  29. #ifndef lint
  30. static char rcsid[] = "$Header: /sprite/src/kernel/recov/RCS/recovery.c,v 9.19 90/10/11 14:10:41 kupfer Exp $ SPRITE (Berkeley)";
  31. #endif /* not lint */
  32.  
  33.  
  34. #include <sprite.h>
  35. #include <recov.h>
  36. #include <sync.h>
  37. #include <net.h>
  38. #include <rpc.h>
  39. #include <hash.h>
  40. #include <stdlib.h>
  41. #include <trace.h>
  42. #include <fsutil.h>
  43. #include <bstring.h>
  44. #include <stdio.h>
  45.  
  46. /*
  47.  * Other kernel modules arrange call-backs when a host crashes or reboots.
  48.  * The following list structure is used to keep these.  The calling
  49.  * sequence of the callbacks is as follows:
  50.  *    (*proc)(spriteID, clientData)
  51.  * Use Recov_CrashRegister and Recov_RebootRegister to set up the call backs.
  52.  */
  53.  
  54. typedef struct {
  55.     List_Links    links;
  56.     void    (*proc)();
  57.     int        refCount;
  58.     ClientData    data;
  59. } NotifyElement;
  60.  
  61. /*
  62.  * There is a single list of crash call backs, it isn't per machine
  63.  * like the reboot callbacks.
  64.  */
  65. static List_Links    crashCallBackList;
  66.  
  67. /*
  68.  * recov_CrashDelay is the grace period given when another host
  69.  * is apparently down.  Reboots are still detected so that
  70.  * the crash callbacks will get called to clean up.
  71.  */
  72. unsigned int recov_CrashDelay;
  73.  
  74. /*
  75.  * Statistics about the recovery module.
  76.  */
  77. Recov_Stats recov_Stats;
  78.  
  79. /*
  80.  * For per-client statistics about recovery on the server.
  81.  * This amounts to a per-host list, in array form.
  82.  * Each host has numTries elements in the array.  The spriteID and numTries
  83.  * fields are only initialized in the first element.
  84.  */
  85. typedef    struct    RecovPerHostInfo {
  86.     int        spriteID;    /* Sprite ID of client. */
  87.     Time    start;        /* First recovery attempt. */
  88.     Time    finished;    /* First recovery attempt finished. */
  89.     int        numTries;    /* Number of recovery attempts. */
  90.     int        numHandles;    /* Number of reopens requested. */
  91.     int        numSuccessful;    /* Handles successfully recovered. */
  92. } RecovPerHostInfo;
  93.  
  94.  
  95.  
  96. /*
  97.  * The state of other hosts is kept in a hash table keyed on SpriteID.
  98.  * This state is maintained by Recov_HostAlive and Recov_HostDead, which are
  99.  * called in turn after packet reception or RPC timeout, respectively.
  100.  * Recov_HostDead is also called by the Rpc_Daemon if it can't get an
  101.  * explicit acknowledgment from a client.
  102.  */
  103. static Hash_Table    recovHashTableStruct;
  104. static Hash_Table    *recovHashTable = &recovHashTableStruct;
  105.  
  106. typedef    struct    RecovStampList {
  107.     List_Links    timeStampList;
  108.     Timer_Ticks    start;
  109.     Timer_Ticks    finished;
  110.     int        numHandles;        /* Handles since last time. */
  111.     int        numSuccessful;        /* Successful last time. */
  112. } RecovStampList;
  113.  
  114. typedef struct RecovHostState {
  115.     int            state;        /* flags defined below */
  116.     int            clientState;    /* flags defined in recov.h */
  117.     int            spriteID;    /* Sprite Host ID */
  118.     unsigned int    bootID;        /* Boot timestamp from RPC header */
  119.     Time        time;        /* Time of last message */
  120.     Sync_Condition    alive;        /* Notified when host comes up */
  121.     Sync_Condition    recovery;    /* Notified when recovery is complete */
  122.     List_Links        rebootList;    /* List of callbacks for when this
  123.                      * host reboots. */
  124.     int            numFailures;    /* Times a failure occurs during the
  125.                      * reboot callbacks.  Such a failure
  126.                      * triggers a retry of the reboot
  127.                      * callbacks. */
  128.     /*
  129.      * The following fields are used in the tracing of the recovery module.
  130.      */
  131.     Timer_Ticks        start;        /* Time that recovery is started. */
  132.     Timer_Ticks        finished;    /* Time recovery attempt  finishes. */
  133.     int            numTries;    /* Number of times recov attempted. */
  134.     int            numHandles;    /* Handles requested. */
  135.     int            numSuccessful;    /* Successful handles. */
  136.     int            currentHandles;    /* Temporary info. */
  137.     int            currentSuccessful;
  138.     List_Links        timeStampList;    /* List of time stamps for recovery. */
  139. } RecovHostState;
  140.  
  141. #define RECOV_INIT_HOST(hostPtr, zspriteID, zstate, zbootID) \
  142.     hostPtr = (RecovHostState *) malloc(sizeof (RecovHostState)); \
  143.     (void)bzero((Address)hostPtr, sizeof(RecovHostState)); \
  144.     List_Init(&(hostPtr)->rebootList); \
  145.     List_Init(&(hostPtr)->timeStampList);\
  146.     (hostPtr)->spriteID = zspriteID; \
  147.     (hostPtr)->state = zstate; \
  148.     (hostPtr)->bootID = zbootID; \
  149.     (hostPtr)->numFailures = 0;
  150.  
  151. /*
  152.  * Access to the hash table is monitored.
  153.  */
  154. static Sync_Lock recovLock;
  155. #define LOCKPTR (&recovLock)
  156.  
  157.  
  158. /*
  159.  * recov_PrintLevel defines how noisey we are about other hosts.
  160.  *    Values for the print level should be defined in increasing order.
  161.  */
  162. int recov_PrintLevel = RECOV_PRINT_REBOOT;
  163.  
  164. #define RecovHostPrint(level, spriteID, message) \
  165.     if (recov_PrintLevel >= level) { \
  166.         Sys_HostPrint(spriteID, message); \
  167.     }
  168.  
  169. Trace_Header recovTraceHdr;
  170. Trace_Header *recovTraceHdrPtr = &recovTraceHdr;
  171. int recovTraceLength = 50;
  172. Boolean recovTracing = TRUE;
  173.  
  174. /*
  175.  * Forward declarations.
  176.  */
  177.  
  178. static void CrashCallBacks _ARGS_((ClientData data, Proc_CallInfo *callInfoPtr));
  179. #ifdef dying_state
  180. static void DelayedCrashCallBacks _ARGS_((ClientData data, Proc_CallInfo *callInfoPtr));
  181. static void MarkHostDead _ARGS_((int spriteID));
  182. #endif /* dying_state */
  183. static void CallBacksDone _ARGS_((int spriteID));
  184. static void MarkRecoveryComplete _ARGS_((int spriteID));
  185. static void GetRebootList _ARGS_((List_Links *notifyListHdr, int spriteID));
  186. static char *GetState _ARGS_((int state));
  187. static void PrintExtraState _ARGS_((RecovHostState *hostPtr));
  188.  
  189.  
  190.  
  191.  
  192. /*
  193.  *----------------------------------------------------------------------
  194.  *
  195.  * Recov_Init --
  196.  *
  197.  *    Set up the data structures used by the recovery module.
  198.  *
  199.  * Results:
  200.  *    None.
  201.  *
  202.  * Side effects:
  203.  *    None.
  204.  *
  205.  *----------------------------------------------------------------------
  206.  */
  207.  
  208. void
  209. Recov_Init()
  210. {
  211.     Sync_LockInitDynamic(&recovLock, "Recov:recovLock");
  212.     Hash_Init(recovHashTable, 8, HASH_ONE_WORD_KEYS);
  213.     List_Init(&crashCallBackList);
  214.     Trace_Init(recovTraceHdrPtr, recovTraceLength,
  215.         sizeof(RecovTraceRecord), 0);
  216.     recov_CrashDelay = (unsigned int)(timer_IntOneMinute);
  217.     RecovPingInit();
  218.     return;
  219. }
  220.  
  221. /*
  222.  *----------------------------------------------------------------------
  223.  *
  224.  * Recov_CrashRegister --
  225.  *
  226.  *    This procedure is used to register a crash callback procedure.
  227.  *    This is typically done once at boot time by each module that
  228.  *    is interested in learning about the failure of other hosts.
  229.  *    When other hosts are (apparently) down the recovery module
  230.  *    calls back to other modules that have registered via this procedure.
  231.  *    This allows those other modules to clean up any state associated
  232.  *    with the crashed host.
  233.  *    
  234.  * Results:
  235.  *    None.
  236.  *
  237.  * Side effects:
  238.  *    Callback entry added to the crash call-back list.
  239.  *
  240.  *----------------------------------------------------------------------
  241.  */
  242. void
  243. Recov_CrashRegister(crashCallBackProc, crashData)
  244.     void    (*crashCallBackProc)();
  245.     ClientData    crashData;
  246. {
  247.     register    NotifyElement    *notifyPtr;
  248.  
  249.     notifyPtr = (NotifyElement *) malloc(sizeof (NotifyElement));
  250.     notifyPtr->proc = crashCallBackProc;
  251.     notifyPtr->data = crashData;
  252.     List_InitElement((List_Links *) notifyPtr);
  253.     List_Insert((List_Links *) notifyPtr, LIST_ATREAR(&crashCallBackList));
  254.     return;
  255. }
  256.  
  257. /*
  258.  *----------------------------------------------------------------------
  259.  *
  260.  * Recov_RebootRegister --
  261.  *
  262.  *    Schedule a callback for when a particular host reboots.
  263.  *    To make sure we detect a crash, the recovery module has to
  264.  *    periodically check on the state of the target host.
  265.  *
  266.  * Results:
  267.  *    None.
  268.  *
  269.  * Side effects:
  270.  *    This initiate a background callback to check-up on the host's state.
  271.  *
  272.  *----------------------------------------------------------------------
  273.  */
  274.  
  275. ENTRY void
  276. Recov_RebootRegister(spriteID, rebootCallBackProc, rebootData)
  277.     int spriteID;
  278.     void (*rebootCallBackProc)();
  279.     ClientData rebootData;
  280. {
  281.     Hash_Entry *hashPtr;
  282.     RecovHostState *hostPtr;
  283.     register NotifyElement *notifyPtr;
  284.     Boolean found = FALSE;
  285.  
  286.     LOCK_MONITOR;
  287.  
  288.     if (spriteID <= 0 || spriteID == rpc_SpriteID) {
  289.     panic("Recov_RebootRegister, bad hostID %d\n", spriteID);
  290.     } else {
  291.     hashPtr = Hash_Find(recovHashTable, (Address)spriteID);
  292.     if (hashPtr->value == (Address)NIL) {
  293.         RECOV_INIT_HOST(hostPtr, spriteID, RECOV_STATE_UNKNOWN, 0);
  294.         hashPtr->value = (Address)hostPtr;
  295.     } else {
  296.         hostPtr = (RecovHostState *)hashPtr->value;
  297.     }
  298.     /*
  299.      * Save the callback while avoiding duplications.
  300.      */
  301.     LIST_FORALL(&hostPtr->rebootList, (List_Links *)notifyPtr) {
  302.         if (notifyPtr->proc == rebootCallBackProc &&
  303.         notifyPtr->data == rebootData) {
  304.         found = TRUE;
  305.         break;
  306.         }
  307.     }
  308.     if (!found) {
  309.         notifyPtr = (NotifyElement *) malloc(sizeof (NotifyElement));
  310.         notifyPtr->proc = rebootCallBackProc;
  311.         notifyPtr->data = rebootData;
  312.         notifyPtr->refCount = 1;
  313.         List_InitElement((List_Links *)notifyPtr);
  314.         List_Insert((List_Links *)notifyPtr,
  315.             LIST_ATFRONT(&hostPtr->rebootList));
  316.     } else {
  317.         notifyPtr->refCount++;
  318.     }
  319.     /*
  320.      * Mark the host as being interesting, and add it to the ping
  321.      * list if necessary.
  322.      */
  323.     hostPtr->state |= RECOV_PINGING_HOST;
  324.     RecovAddHostToPing(spriteID);
  325.     }
  326.     UNLOCK_MONITOR;
  327.     return;
  328. }
  329.  
  330. /*
  331.  *----------------------------------------------------------------------
  332.  *
  333.  * Recov_RebootUnRegister --
  334.  *
  335.  *    Remove a callback for when a particular host reboots.  This is
  336.  *    used after we are no longer interested in a host rebooting.
  337.  *
  338.  * Results:
  339.  *    None.
  340.  *
  341.  * Side effects:
  342.  *    Nukes the reboot procedure.  If all interested parties remove their
  343.  *    reboot callbacks then the periodic check of the other host is
  344.  *    stopped.
  345.  *
  346.  *----------------------------------------------------------------------
  347.  */
  348.  
  349. ENTRY void
  350. Recov_RebootUnRegister(spriteID, rebootCallBackProc, rebootData)
  351.     int spriteID;
  352.     void (*rebootCallBackProc)();
  353.     ClientData rebootData;
  354. {
  355.     Hash_Entry *hashPtr;
  356.     RecovHostState *hostPtr;
  357.     register NotifyElement *notifyPtr;
  358.     Boolean found = FALSE;
  359.  
  360.     LOCK_MONITOR;
  361.  
  362.     if (spriteID <= 0 || spriteID == rpc_SpriteID) {
  363.     panic("Recov_RebootUnRegister, bad hostID %d\n", spriteID);
  364.     } else {
  365.     hashPtr = Hash_Find(recovHashTable, (Address)spriteID);
  366.     if (hashPtr->value == (Address)NIL) {
  367.         RECOV_INIT_HOST(hostPtr, spriteID, RECOV_STATE_UNKNOWN, 0);
  368.         hashPtr->value = (Address)hostPtr;
  369.     } else {
  370.         hostPtr = (RecovHostState *)hashPtr->value;
  371.     }
  372.     /*
  373.      * Look for the matching callback.
  374.      */
  375.     LIST_FORALL(&hostPtr->rebootList, (List_Links *)notifyPtr) {
  376.         if (notifyPtr->proc == rebootCallBackProc &&
  377.         notifyPtr->data == rebootData) {
  378.         found = TRUE;
  379.         break;
  380.         }
  381.     }
  382.     if (found) {
  383.         notifyPtr->refCount--;
  384.         if (notifyPtr->refCount <= 0) {
  385.         int        num;
  386.         /*
  387.          * Mousetrap for debugging recovery reference count problem.
  388.          */
  389.         if (notifyPtr->proc == (void((*)())) Fsutil_Reopen) {
  390.  
  391.             if (recov_PrintLevel >= RECOV_PRINT_CRASH) {
  392.             printf(
  393.         "Recov: deleting Fsutil_Reopen for server %d ref count %d\n",
  394.                 spriteID, notifyPtr->refCount);
  395.             }
  396.             /*
  397.              * We want to panic if we still have handles for
  398.              * this server.
  399.              */
  400.             num = Fsutil_TestForHandles(spriteID);
  401.             /*
  402.              * This routine is called before the handle is removed,
  403.              * so we must take into account the fact that it still
  404.              * exists in the handle table.
  405.              */
  406.             if (num > 1) {
  407.             printf("%d file and device handles remain\n", num);
  408.             panic("Shouldn't have deleted it - handles remain!\n");
  409.             }
  410.         }
  411.         List_Remove((List_Links *)notifyPtr);
  412.         free((Address)notifyPtr);
  413.         }
  414.     }
  415.     }
  416.     UNLOCK_MONITOR;
  417.     return;
  418. }
  419.  
  420. /*
  421.  *----------------------------------------------------------------------
  422.  *
  423.  * Recov_HostAlive --
  424.  *
  425.  *    Mark the host as being alive.  This is called when we've received
  426.  *    a message from the host.  It uses state from the host table and
  427.  *    the bootID parameter to detect reboots.  If a reboot is detected,
  428.  *    but we thought the host was up, then the Crash call-backs are invoked.
  429.  *    In any case, a reboot invokes the Reboot call-backs, if any.
  430.  *
  431.  *    This procedure is called from client RPC upon successful completion
  432.  *    of an RPC, and by server RPC upon reciept of a client request.
  433.  *    These two cases are identified by the 'asyncRecovery' parameter.
  434.  *    Servers want synchronous recovery so they don't service anything
  435.  *    until state associated with that client has been cleaned up via
  436.  *    the Crash call-backs.  So Recov_HostAlive blocks (if !asyncRecovery)
  437.  *    until the crash call-backs are complete.  Clients don't have the
  438.  *    same worries so they let the crash call-backs complete in the
  439.  *    background (asyncRecovery is TRUE).
  440.  *
  441.  * Results:
  442.  *    None.
  443.  *
  444.  * Side effects:
  445.  *    Updates the boot timestamp of the other host.  Procedures installed
  446.  *    with Recov_CrashRegister are called when the bootID changes.  A
  447.  *    timestamp of when this message was received is obtained from the
  448.  *    "cheap" clock so we can tell later if there has been recent message
  449.  *    traffic.
  450.  *
  451.  *----------------------------------------------------------------------
  452.  */
  453.  
  454. ENTRY void
  455. Recov_HostAlive(spriteID, bootID, asyncRecovery, rpcNotActive)
  456.     int spriteID;        /* Host ID of the message sender */
  457.     unsigned int bootID;    /* Boot time stamp from message header */
  458.     Boolean asyncRecovery;    /* TRUE means do recovery call-backs in
  459.                  * the background. FALSE causes the process
  460.                  * to wait until crash recovery is complete. */
  461.     Boolean rpcNotActive;    /* This is a flag propogated from the rpc
  462.                  * packet header.  If set it means the RPC
  463.                  * system on the remote host isn't fully
  464.                  * turned on.  Reboot recovery is delayed
  465.                  * until this changes. */
  466. {
  467.     register Hash_Entry *hashPtr;
  468.     register RecovHostState *hostPtr;
  469.  
  470.     LOCK_MONITOR;
  471.     if (spriteID == NET_BROADCAST_HOSTID || bootID == 0 || sys_ShuttingDown) {
  472.     /*
  473.      * Don't track the broadcast address.  Also ignore zero valued
  474.      * bootIDs.  These come from hosts at early boot time, or
  475.      * in certain error conditions like trying to send too much
  476.      * data in a single RPC.  Also don't bother to check things
  477.      * where we are shutting down the system because we don't want 
  478.      * RPCs for the cache data to get blocked.
  479.      */
  480.     UNLOCK_MONITOR;
  481.     return;
  482.     }
  483.  
  484.     recov_Stats.packets++;
  485.     hashPtr = Hash_Find(recovHashTable, (Address)spriteID);
  486.     if (hashPtr->value == (Address)NIL) {
  487.     /*
  488.      * Initialize the host's state. This is the first time we've talked
  489.      * to it since we've been up, so take no action.
  490.      */
  491.     RECOV_INIT_HOST(hostPtr, spriteID, RECOV_HOST_ALIVE, bootID);
  492.     hashPtr->value = (Address)hostPtr;
  493.  
  494.     RecovHostPrint(RECOV_PRINT_IF_UP, spriteID, "is up\n");
  495.     RECOV_TRACE(spriteID, RECOV_HOST_ALIVE, RECOV_CUZ_INIT);
  496.     } else {
  497.     hostPtr = (RecovHostState *)hashPtr->value;
  498.     }
  499.     /*
  500.      * Have to read the clock in order to suppress repeated pings,
  501.      * see Recov_GetHostState and Recov_IsHostDown.
  502.      */
  503.     Timer_GetTimeOfDay(&hostPtr->time, (int *)NIL, (Boolean *)NIL);
  504.     /*
  505.      * Check for a rebooted peer by comparing boot time stamps.
  506.      */
  507.     if (hostPtr->bootID != bootID) {
  508.     if (hostPtr->bootID != 0) {
  509.         RecovHostPrint(RECOV_PRINT_REBOOT, spriteID, "rebooted\n");
  510.     } else {
  511.         /*
  512.          * We initialized state before talking to the host the first time.
  513.          * The state is 'unknown' so we won't do crash call-backs.
  514.          */
  515.     }
  516.     hostPtr->bootID = bootID;
  517.     RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_REBOOT);
  518.     if (hostPtr->state &
  519.         (RECOV_HOST_ALIVE|RECOV_HOST_DYING|RECOV_HOST_BOOTING)) {
  520.         RecovHostPrint(RECOV_PRINT_ALL, spriteID,
  521.             "Undetected crash occurred.\n");
  522.         /*
  523.          * A crash occured un-detected.  We do the crash call-backs
  524.          * first, and block server processes in the meantime.
  525.          * RECOV_CRASH_CALLBACKS flag is cleared by CrashCallBacks.
  526.          */
  527.         hostPtr->state &=
  528.             ~(RECOV_HOST_ALIVE|RECOV_HOST_DYING|RECOV_HOST_DEAD);
  529.         hostPtr->state |= RECOV_HOST_BOOTING;
  530.         RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_CRASH_UNDETECTED);
  531.         if ((hostPtr->state & RECOV_CRASH_CALLBACKS) == 0) {
  532.         hostPtr->state |= RECOV_CRASH_CALLBACKS;
  533.         RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_CRASH_UNDETECTED);
  534.         Proc_CallFunc(CrashCallBacks, (ClientData)spriteID, 0);
  535.         }
  536.     }
  537.     } else  if ( ! (hostPtr->state &
  538.         (RECOV_CRASH_CALLBACKS|RECOV_WANT_RECOVERY)) &&
  539.         (hostPtr->state & RECOV_HOST_ALIVE)) {
  540.     /*
  541.      * Fast path.  We already think the other host is up, it didn't
  542.      * reboot, we don't want recovery, and there are no pending
  543.      * crash call-backs to synchronize with.
  544.      */
  545.     goto exit;
  546.     }
  547.     /*
  548.      * Block servers until crash recovery actions complete.
  549.      * This prevents servicing requests from clients until after the
  550.      * recovery actions complete.
  551.      */
  552.     if (! asyncRecovery) {
  553.     RecovHostPrint(RECOV_PRINT_ALL, spriteID, "Async recovery false.\n");
  554.     while (hostPtr->state & RECOV_CRASH_CALLBACKS) {
  555.         (void)Sync_Wait(&hostPtr->recovery, FALSE);
  556.         if (sys_ShuttingDown) {
  557.         UNLOCK_MONITOR;
  558.         Proc_Exit(1);
  559.         }
  560.     }
  561.     }
  562.     /*
  563.      * Now that we've taken care of crash recovery, we see if the host
  564.      * is newly up.  If so, invoke any reboot call-backs and notify
  565.      * waiting processes. This means clientA (us) may start
  566.      * re-opening files from serverB (the other guy) at the same time
  567.      * as clientA (us) is closing files that serverB had had open.
  568.      * ie. both the crash and reboot call backs may proceed in parallel.
  569.      */
  570.     switch(hostPtr->state &
  571.        (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING|RECOV_HOST_DEAD|RECOV_HOST_DYING)) {
  572.         case RECOV_STATE_UNKNOWN:    /* This is zero, no bits set */
  573.         /*
  574.          * We have uninitialized state for the host, mark it alive.
  575.          */
  576.         RecovHostPrint(RECOV_PRINT_IF_UP, spriteID, "is up\n");
  577.         if (rpcNotActive) {
  578.         hostPtr->state |= RECOV_HOST_BOOTING;
  579.         } else {
  580.         hostPtr->state |= RECOV_HOST_ALIVE;
  581.         }
  582.         break;
  583.     case RECOV_HOST_ALIVE:
  584.         /*
  585.          * Host already alive.  We may still want recovery at this
  586.          * point.  See CallBacksDone.
  587.          */
  588.         RecovHostPrint(RECOV_PRINT_ALL, spriteID, "Already up.\n");
  589.         break;
  590.     case RECOV_HOST_BOOTING:
  591.         /*
  592.          * See if a booting host is ready yet.
  593.          */
  594.         RecovHostPrint(RECOV_PRINT_ALL, spriteID, "Booting, set recov.\n");
  595.         if (! rpcNotActive) {
  596.         hostPtr->state &= ~RECOV_HOST_BOOTING;
  597.         hostPtr->state |= RECOV_HOST_ALIVE|RECOV_WANT_RECOVERY;
  598.         RecovHostPrint(RECOV_PRINT_ALL, spriteID,
  599.             "Booting, set alive, recov.\n");
  600.         }
  601.         break;
  602.     case RECOV_HOST_DYING:
  603.     case RECOV_HOST_DEAD:
  604.         /*
  605.          * See if the host is newly booting or back from a net partition.
  606.          */
  607.         if (rpcNotActive) {
  608.         hostPtr->state |= RECOV_HOST_BOOTING;
  609.         RecovHostPrint(RECOV_PRINT_ALL, spriteID,
  610.             "Dead or dying, set booting.\n");
  611.         } else {
  612.         hostPtr->state |= (RECOV_HOST_ALIVE|RECOV_WANT_RECOVERY);
  613.         RecovHostPrint(RECOV_PRINT_ALL, spriteID,
  614.             "Dead, dying, set want recov.\n");
  615.         }
  616.         hostPtr->state &= ~(RECOV_HOST_DEAD|RECOV_HOST_DYING);
  617.         break;
  618.     default:
  619.         printf("Unexpected recovery state <%x> for ", hostPtr->state);
  620.         Sys_HostPrint(spriteID, "\n");
  621.         break;
  622.     }
  623.     /*
  624.      * After a host comes up enough to support RPC service, we
  625.      * initiate reboot recovery if needed.
  626.      */
  627.     if ((hostPtr->state & RECOV_WANT_RECOVERY) &&
  628.     (hostPtr->state & RECOV_HOST_ALIVE) &&
  629.     (hostPtr->state & RECOV_REBOOT_CALLBACKS) == 0) {
  630.     hostPtr->state &= ~RECOV_WANT_RECOVERY;
  631.     hostPtr->state |= RECOV_REBOOT_CALLBACKS;
  632.     RecovHostPrint(RECOV_PRINT_ALL, spriteID,
  633.         "Want recov, etc, callbacks.\n");
  634.     Proc_CallFunc(RecovRebootCallBacks, (ClientData)spriteID, 0);
  635.     }
  636. exit:
  637.     UNLOCK_MONITOR;
  638.     return;
  639. }
  640.  
  641. /*
  642.  *----------------------------------------------------------------------
  643.  *
  644.  * Recov_HostDead --
  645.  *
  646.  *    Change the host's state to "dead".  This is called from client RPC
  647.  *    when an RPC timed out with no response.  It is also called by the
  648.  *    Rpc_Daemon when it can't recontact a client to get an explicit
  649.  *    acknowledgment.
  650.  *
  651.  * Results:
  652.  *    None.
  653.  *
  654.  * Side effects:
  655.  *    If the host was previously thought up, this sets the state in
  656.  *    the host state table to dead and invokes the crash callbacks.
  657.  *
  658.  *----------------------------------------------------------------------
  659.  */
  660.  
  661. ENTRY void
  662. Recov_HostDead(spriteID)
  663.     int spriteID;
  664. {
  665.     register Hash_Entry *hashPtr;
  666.     register RecovHostState *hostPtr;
  667.  
  668.     LOCK_MONITOR;
  669.     if (spriteID == NET_BROADCAST_HOSTID || rpc_NoTimeouts) {
  670.     /*
  671.      * If rpcNoTimeouts is set the Rpc_Daemon may still call us if
  672.      * it can't get an acknowledgment from a host to close down
  673.      * a connection.  We ignore this so that we don't take action
  674.      * against the offending host (who is probably in the debugger)
  675.      * (Hmm, it doesn't look like Rpc_Daemon calls this procedure.)
  676.      */
  677.     UNLOCK_MONITOR;
  678.     return;
  679.     }
  680.  
  681.     recov_Stats.timeouts++;
  682.     hashPtr = Hash_Find(recovHashTable, (Address)spriteID);
  683.     if (hashPtr->value == (Address)NIL) {
  684.     RECOV_INIT_HOST(hostPtr, spriteID, RECOV_HOST_DEAD, 0);
  685.     hashPtr->value = (Address)hostPtr;
  686.     } else {
  687.     hostPtr = (RecovHostState *)hashPtr->value;
  688.     }
  689.     switch(hostPtr->state &
  690.         (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING|RECOV_HOST_DEAD)) {
  691.     case RECOV_HOST_DEAD:
  692.     case RECOV_HOST_DYING:
  693.         /*
  694.          * Host already dead or dying.
  695.          */
  696.         break;
  697.     case RECOV_STATE_UNKNOWN:
  698.     case RECOV_HOST_BOOTING:
  699.     case RECOV_HOST_ALIVE:
  700.         hostPtr->state &=
  701.         ~(RECOV_HOST_ALIVE|RECOV_HOST_BOOTING);
  702.         /*
  703.          * Special handling if we abort during the recovery protocol.
  704.          * In this case it is possible for the other host to go from
  705.          * alive to dead and back to alive before the recovery protocol
  706.          * finally terminates.  If that happens we could loose a reboot
  707.          * event and fail to initiate recovery again.  We mark the
  708.          * host specially so the reboot callbacks are retried.
  709.          */
  710.         if (hostPtr->state & RECOV_REBOOT_CALLBACKS) {
  711.         hostPtr->state |= RECOV_FAILURE;
  712.         }
  713.         /*
  714.          * After an RPC timeout (which is already logged by RPC to syslog)
  715.          * make the crash call backs.  These are made after a delay
  716.          * if dying_state is defined.  This helps smooth over temporary
  717.          * communication failures.
  718.          *
  719.          */
  720. #ifdef dying_state
  721.         hostPtr->state |= RECOV_HOST_DYING;
  722.         Proc_CallFunc(DelayedCrashCallBacks, (ClientData)spriteID,
  723.                 recov_CrashDelay);
  724. #else
  725.         hostPtr->state |= RECOV_HOST_DEAD|RECOV_CRASH_CALLBACKS;
  726.         RecovHostPrint(RECOV_PRINT_CRASH, spriteID,
  727.             "crash call-backs made\n");
  728.         RECOV_TRACE(spriteID, hostPtr->state, RECOV_CUZ_CRASH);
  729.         Proc_CallFunc(CrashCallBacks, (ClientData)spriteID, 0);
  730. #endif
  731.         break;
  732.     }
  733.     UNLOCK_MONITOR;
  734.     return;
  735. }
  736.  
  737. /*
  738.  *----------------------------------------------------------------------
  739.  *
  740.  * Recov_IsHostDown --
  741.  *
  742.  *    This decides if the specified host is down.  If the host is known
  743.  *    to be down this routine    returns FAILURE.  SUCCESS is returned if
  744.  *    the host is alive, and RPC_SERVICE_DISABLED is returned if the
  745.  *    host is in its boot sequence and can't service RPC's yet.  If there
  746.  *    hasn't been recent (within the last 10 seconds) message traffic
  747.  *    this this pings the host to find out for sure its state.
  748.  *
  749.  * Results:
  750.  *    SUCCESS if the host is up, FAILURE if it doesn't respond to
  751.  *    pings or is known to be down, and RPC_SERVICE_DISABLED if
  752.  *    the host says so.
  753.  *
  754.  * Side effects:
  755.  *    May do a ping.
  756.  *
  757.  *----------------------------------------------------------------------
  758.  */
  759.  
  760. ReturnStatus
  761. Recov_IsHostDown(spriteID)
  762.     int spriteID;
  763. {
  764.     register ReturnStatus status = SUCCESS;
  765.  
  766.     if (spriteID == NET_BROADCAST_HOSTID) {
  767.     printf("Warning: Recov_IsHostDown, got broadcast address\n");
  768.     return(SUCCESS);
  769.     }
  770.     switch (Recov_GetHostState(spriteID)) {
  771.     case RECOV_STATE_UNKNOWN:
  772.         RECOV_TRACE(spriteID, RECOV_STATE_UNKNOWN, RECOV_CUZ_PING_ASK);
  773.         recov_Stats.pings++;
  774.         status = Rpc_Ping(spriteID);
  775.         break;
  776.     case RECOV_HOST_BOOTING:
  777.     case RECOV_HOST_ALIVE:
  778.     case RECOV_HOST_DYING:    /* fake it to allow for the grace period */
  779.         recov_Stats.pingsSuppressed++;
  780.         status = SUCCESS;
  781.         break;
  782.     case RECOV_HOST_DEAD:
  783.         status = FAILURE;
  784.         break;
  785.     }
  786.     return(status);
  787. }
  788.  
  789. /*
  790.  *----------------------------------------------------------------------
  791.  *
  792.  * Recov_HostTrace --
  793.  *
  794.  *    Add an entry to the recovery trace.
  795.  *
  796.  * Results:
  797.  *    None.
  798.  *
  799.  * Side effects:
  800.  *    None.
  801.  *
  802.  *----------------------------------------------------------------------
  803.  */
  804.  
  805. ENTRY void
  806. Recov_HostTrace(spriteID, event)
  807.     int spriteID;
  808.     int event;
  809. {
  810.     /*
  811.      * No monitor lock needed here, since Trace_Insert does its own
  812.      * synchronization.
  813.      */
  814.     RECOV_TRACE(spriteID, RECOV_STATE_UNKNOWN, event);
  815. }
  816.  
  817. /*
  818.  *----------------------------------------------------------------------
  819.  *
  820.  * Recov_GetClientState --
  821.  *
  822.  *    Return the client state associated with a host.  The recovery host
  823.  *    table is a convenient object keyed on spriteID.  Other modules can
  824.  *    set their own state in the table (beyond the simple up/down state
  825.  *    mainted by the rest of this module), and retrieve it with this call.
  826.  *
  827.  * Results:
  828.  *    A copy of the clientState field.  0 is returned if there is no
  829.  *    host table entry.
  830.  *
  831.  * Side effects:
  832.  *    None.
  833.  *
  834.  *----------------------------------------------------------------------
  835.  */
  836.  
  837. ENTRY int
  838. Recov_GetClientState(spriteID)
  839.     int spriteID;
  840. {
  841.     Hash_Entry *hashPtr;
  842.     RecovHostState *hostPtr;
  843.     int stateBits = 0;
  844.  
  845.     LOCK_MONITOR;
  846.  
  847.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  848.     if (hashPtr != (Hash_Entry *)NIL) {
  849.     hostPtr = (RecovHostState *)hashPtr->value;
  850.     if (hostPtr != (RecovHostState *)NIL) {
  851.         stateBits = hostPtr->clientState;
  852.     }
  853.     }
  854.     UNLOCK_MONITOR;
  855.     return(stateBits);
  856. }
  857.  
  858. /*
  859.  *----------------------------------------------------------------------
  860.  *
  861.  * Recov_SetClientState --
  862.  *
  863.  *    Set a client state bit.  This or's the parameter into the
  864.  *    client state word.  The previous value of the client state
  865.  *    word is returned so this procedure can be used like test-and-set.
  866.  *
  867.  * Results:
  868.  *    None.
  869.  *
  870.  * Side effects:
  871.  *    Sets bits in the clientState field of the host state.  This will add
  872.  *    an entry to the host table if one doesn't alreay exist.  Its RPC
  873.  *    up/down state is set to "unknown" in this case.
  874.  *
  875.  *----------------------------------------------------------------------
  876.  */
  877.  
  878. ENTRY int
  879. Recov_SetClientState(spriteID, stateBits)
  880.     int spriteID;
  881.     int stateBits;
  882. {
  883.     Hash_Entry *hashPtr;
  884.     RecovHostState *hostPtr;
  885.     register oldState;
  886.     RecovStampList    *stampPtr;
  887.  
  888.     LOCK_MONITOR;
  889.  
  890.     hashPtr = Hash_Find(recovHashTable, (Address)spriteID);
  891.     hostPtr = (RecovHostState *)hashPtr->value;
  892.     if (hostPtr == (RecovHostState *)NIL) {
  893.     RECOV_INIT_HOST(hostPtr, spriteID, RECOV_STATE_UNKNOWN, 0);
  894.     hashPtr->value = (Address)hostPtr;
  895.     }
  896.     if ((stateBits & CLT_RECOV_IN_PROGRESS) != 0) {
  897.     if (hostPtr->numTries == 0) {
  898.         /* First recovery attempt */
  899.         if ((hostPtr->clientState & CLT_RECOV_IN_PROGRESS) != 0) {
  900.         printf("No recovery attempt yet, but marked as in progress.");
  901.         }
  902.         Timer_GetCurrentTicks(&hostPtr->start);
  903.     } else {
  904.         /* Add a time-stamp to the recovery list. */
  905.         stampPtr = (RecovStampList *) malloc(sizeof (RecovStampList));
  906.         Timer_GetCurrentTicks(&stampPtr->start);
  907.         List_InitElement((List_Links *) stampPtr);
  908.         List_Insert((List_Links *) stampPtr,
  909.             LIST_ATREAR(&hostPtr->timeStampList));
  910.         /*
  911.          * Clear handle count for this round.
  912.          */
  913.         hostPtr->currentHandles = 0;
  914.         hostPtr->currentSuccessful = 0;
  915.     }
  916.     hostPtr->numTries++;
  917.     }
  918.  
  919.     oldState = hostPtr->clientState;
  920.     hostPtr->clientState |= stateBits;
  921.     UNLOCK_MONITOR;
  922.     return(oldState);
  923. }
  924.  
  925. /*
  926.  *----------------------------------------------------------------------
  927.  *
  928.  * Recov_ClearClientState --
  929.  *
  930.  *    Clear client state bits.
  931.  *
  932.  * Results:
  933.  *    None.
  934.  *
  935.  * Side effects:
  936.  *    Clears bits in the clientState field of the host state.  This does
  937.  *    nothing if the state doesn't exist.
  938.  *
  939.  *----------------------------------------------------------------------
  940.  */
  941.  
  942. ENTRY void
  943. Recov_ClearClientState(spriteID, stateBits)
  944.     int spriteID;
  945.     int stateBits;
  946. {
  947.     register Hash_Entry        *hashPtr;
  948.     register RecovHostState    *hostPtr = (RecovHostState *) NIL;
  949.     RecovStampList        *stampPtr;
  950.  
  951.     LOCK_MONITOR;
  952.  
  953.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  954.     if (hashPtr != (Hash_Entry *)NIL) {
  955.     hostPtr = (RecovHostState *)hashPtr->value;
  956.     if (hostPtr != (RecovHostState *)NIL) {
  957.         hostPtr->clientState &= ~stateBits;
  958.     }
  959.     }
  960.     /* End of recovery? */
  961.     if ((hostPtr != (RecovHostState *) NIL) &&
  962.         (stateBits & CLT_RECOV_IN_PROGRESS) != 0) {
  963.     /* End of 1st recovery try? */
  964.     if (hostPtr->numTries <= 1) {
  965.         Timer_GetCurrentTicks(&hostPtr->finished);
  966.         /* Final count of handles recovered is in hostPtr. */
  967.         hostPtr->numHandles = hostPtr->currentHandles;
  968.         hostPtr->numSuccessful = hostPtr->currentSuccessful;
  969.     } else {
  970.         if (List_IsEmpty(&hostPtr->timeStampList)) {
  971.         printf("Recov_ClearClientState: timeStampList is empty!\n");
  972.         hostPtr->numSuccessful = 0;    /* signal the error */
  973.         } else {
  974.         stampPtr = (RecovStampList *)
  975.             List_Last((List_Links *) &hostPtr->timeStampList);
  976.         Timer_GetCurrentTicks(&stampPtr->finished);
  977.         stampPtr->numHandles = hostPtr->currentHandles;
  978.         stampPtr->numSuccessful = hostPtr->currentSuccessful;
  979.         }
  980.     }
  981.     }
  982.     UNLOCK_MONITOR;
  983.     return;
  984. }
  985.  
  986.  
  987. /*
  988.  *----------------------------------------------------------------------
  989.  *
  990.  * Recov_AddHandleCountToClientState --
  991.  *
  992.  *    Increment count of handles reopened from this client.
  993.  *
  994.  * Results:
  995.  *    None.
  996.  *
  997.  * Side effects:
  998.  *    Data in per-host recovery info updated.
  999.  *
  1000.  *----------------------------------------------------------------------
  1001.  */
  1002. ENTRY void
  1003. Recov_AddHandleCountToClientState(type, clientID, status)
  1004.     int            type;        /* Type of handle being reopened. */
  1005.     int            clientID;    /* Id of client requesting reopen. */
  1006.     ReturnStatus    status;        /* Whether the reopen succeeded. */
  1007. {
  1008.     register Hash_Entry *hashPtr;
  1009.     register RecovHostState *hostPtr = (RecovHostState *) NIL;
  1010.  
  1011.     LOCK_MONITOR;
  1012.  
  1013.     hashPtr = Hash_LookOnly(recovHashTable, (Address)clientID);
  1014.     if (hashPtr != (Hash_Entry *)NIL) {
  1015.     hostPtr = (RecovHostState *)hashPtr->value;
  1016.     if (hostPtr != (RecovHostState *)NIL) {
  1017.         hostPtr->currentHandles++;
  1018.         if (status == SUCCESS) {
  1019.         hostPtr->currentSuccessful++;
  1020.         }
  1021.     }
  1022.     }
  1023.     UNLOCK_MONITOR;
  1024.     return;
  1025. }
  1026.  
  1027.  
  1028. /*
  1029.  *----------------------------------------------------------------------
  1030.  *
  1031.  * Recov_DumpClientRecovInfo --
  1032.  *
  1033.  *    Dump out some of the recovery statistics in the per-host info.
  1034.  *
  1035.  * Results:
  1036.  *    Returns FAILURE if recovery still in progress.  Returns SUCCESS
  1037.  *    otherwise.
  1038.  *
  1039.  * Side effects:
  1040.  *    Info copied into buffer.  Size of needed buffer also copied out.
  1041.  *
  1042.  *----------------------------------------------------------------------
  1043.  */
  1044. ENTRY ReturnStatus
  1045. Recov_DumpClientRecovInfo(length, resultPtr, lengthNeededPtr)
  1046.     int            length;            /* size of data buffer */
  1047.     Address        resultPtr;        /* Array of info structs. */
  1048.     int            *lengthNeededPtr;    /* to return space needed */
  1049. {
  1050.     Hash_Entry        *hashPtr;
  1051.     RecovHostState    *hostPtr;
  1052.     Hash_Search        hashSearch;
  1053.     RecovPerHostInfo    *infoPtr;
  1054.     int            numNeeded;
  1055.     int            numAvail;
  1056.  
  1057.     LOCK_MONITOR;
  1058.  
  1059.     /*
  1060.      * If recovery still going on, return FAILURE.
  1061.      * NOTE: This isn't a sure-fire test.  I'm not sure there is one right now.
  1062.      */
  1063.     if (fsutil_NumRecovering >= 1) {
  1064.     UNLOCK_MONITOR;
  1065.     return FAILURE;
  1066.     }
  1067.     if (resultPtr != (Address) NIL) {
  1068.     bzero(resultPtr, length);
  1069.     }
  1070.     numNeeded = 0;
  1071.     numAvail = length / sizeof (RecovPerHostInfo);
  1072.  
  1073.     infoPtr = (RecovPerHostInfo *) resultPtr;
  1074.     Hash_StartSearch(&hashSearch);
  1075.     for (hashPtr = Hash_Next(recovHashTable, &hashSearch);
  1076.         hashPtr != (Hash_Entry *) NIL;
  1077.         hashPtr = Hash_Next(recovHashTable, &hashSearch)) {
  1078.     hostPtr = (RecovHostState *)hashPtr->value;
  1079.  
  1080.     /*
  1081.      * We need one slot for each host, whether numTries is 0 or 1, plus
  1082.      * additional slots for each numTries over 1.
  1083.      */
  1084.     numNeeded++;
  1085.     if (hostPtr->numTries > 1) {
  1086.         numNeeded += (hostPtr->numTries - 1);
  1087.     }
  1088.     if (numNeeded > numAvail) {
  1089.         continue;
  1090.     }
  1091.     /* Why didn't Brent use GetValue()??? */
  1092.     if (hostPtr != (RecovHostState *) NIL) {
  1093.         RecovStampList    *stampPtr;
  1094.  
  1095.         /* Copy info into buffer */
  1096.         infoPtr->spriteID = hostPtr->spriteID;
  1097.         infoPtr->numTries = hostPtr->numTries;
  1098.         Timer_GetRealTimeFromTicks(hostPtr->start,
  1099.             &(infoPtr->start), (int *) NIL, (Boolean *) NIL);
  1100.         Timer_GetRealTimeFromTicks(hostPtr->finished,
  1101.             &(infoPtr->finished), (int *)NIL, (Boolean *) NIL);
  1102.         infoPtr->numHandles = hostPtr->numHandles;
  1103.         infoPtr->numSuccessful = hostPtr->numSuccessful;
  1104.         LIST_FORALL(&hostPtr->timeStampList, (List_Links *) stampPtr) {
  1105.         infoPtr++;
  1106.         Timer_GetRealTimeFromTicks(stampPtr->start,
  1107.             &infoPtr->start, (int *) NIL, (Boolean *) NIL);
  1108.         Timer_GetRealTimeFromTicks(stampPtr->finished,
  1109.             &infoPtr->finished, (int *) NIL, (Boolean *) NIL);
  1110.         infoPtr->numHandles = stampPtr->numHandles;
  1111.         infoPtr->numSuccessful = stampPtr->numSuccessful;
  1112.         }
  1113.     }
  1114.     infoPtr++;
  1115.     }
  1116.     *lengthNeededPtr = numNeeded * sizeof (RecovPerHostInfo);
  1117.     UNLOCK_MONITOR;
  1118.  
  1119.     return SUCCESS;
  1120. }
  1121.  
  1122. /*
  1123.  *----------------------------------------------------------------------
  1124.  *
  1125.  * RecovRebootCallBacks --
  1126.  *
  1127.  *    This calls the call-back procedures installed by other modules
  1128.  *    via Recov_RebootRegister.  It is invoked asynchronously from
  1129.  *    Recov_HostAlive when that procedure detects a reboot.
  1130.  *
  1131.  * Results:
  1132.  *    None.
  1133.  *
  1134.  * Side effects:
  1135.  *    Invoke the call-backs.
  1136.  *
  1137.  *----------------------------------------------------------------------
  1138.  */
  1139. /*ARGSUSED*/
  1140. void
  1141. RecovRebootCallBacks(data, callInfoPtr)
  1142.     ClientData data;
  1143.     Proc_CallInfo *callInfoPtr;
  1144. {
  1145.     List_Links notifyList;
  1146.     register NotifyElement *notifyPtr;
  1147.     register int spriteID = (int)data;
  1148.  
  1149.     GetRebootList(¬ifyList, spriteID);
  1150.     recov_Stats.reboots++;
  1151.     while (!List_IsEmpty(¬ifyList)) {
  1152.     notifyPtr = (NotifyElement *)List_First(¬ifyList);
  1153.     (*notifyPtr->proc)(spriteID, notifyPtr->data);
  1154.     List_Remove((List_Links *)notifyPtr);
  1155.     free((Address)notifyPtr);
  1156.     }
  1157.     CallBacksDone(spriteID);
  1158.     return;
  1159. }
  1160.  
  1161. /*
  1162.  *----------------------------------------------------------------------
  1163.  *
  1164.  * GetRebootList --
  1165.  *
  1166.  *    Copy out the list of reboot callbacks.  The list is protected by
  1167.  *     a monitor, but we don't want to call any recovery procedures from
  1168.  *    inside that monitor so we make a copy.
  1169.  *
  1170.  * Results:
  1171.  *    None.
  1172.  *
  1173.  * Side effects:
  1174.  *    Copy the reboot list off the host state table and return it
  1175.  *    to our caller who should free up the copied elements.
  1176.  *
  1177.  *----------------------------------------------------------------------
  1178.  */
  1179.  
  1180. ENTRY static void
  1181. GetRebootList(notifyListHdr, spriteID)
  1182.     List_Links *notifyListHdr;
  1183.     int spriteID;
  1184. {
  1185.     register Hash_Entry *hashPtr;
  1186.     register RecovHostState *hostPtr;
  1187.     register NotifyElement *notifyPtr;
  1188.     register NotifyElement *newNotifyPtr;
  1189.  
  1190.     LOCK_MONITOR;
  1191.  
  1192.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1193.     hostPtr = (RecovHostState *)hashPtr->value;
  1194.     List_Init(notifyListHdr);
  1195.     LIST_FORALL(&hostPtr->rebootList, (List_Links *)notifyPtr) {
  1196.     newNotifyPtr = (NotifyElement *) malloc(sizeof (NotifyElement));
  1197.     newNotifyPtr->proc = notifyPtr->proc;
  1198.     newNotifyPtr->data = notifyPtr->data;
  1199.     List_InitElement((List_Links *)newNotifyPtr);
  1200.     List_Insert((List_Links *)newNotifyPtr, LIST_ATREAR(notifyListHdr));
  1201.     }
  1202.     UNLOCK_MONITOR;
  1203.     return;
  1204. }
  1205.  
  1206. /*
  1207.  *----------------------------------------------------------------------
  1208.  *
  1209.  * CallBacksDone --
  1210.  *
  1211.  *    Clear the internal state bit that says callbacks are in progress.
  1212.  *    This checks to see if there was a communication failure during
  1213.  *    the reboot callbacks.  If so, the WANT_RECOVERY bit is set
  1214.  *    to ensure that another set of reboot callbacks are made.
  1215.  *
  1216.  * Results:
  1217.  *    None.
  1218.  *
  1219.  * Side effects:
  1220.  *    Clears RECOV_REBOOT_CALLBACKS and RECOV_FAILURE.  May set
  1221.  *    RECOV_WANT_RECOVERY if RECOV_FAILURE was set.
  1222.  *
  1223.  *----------------------------------------------------------------------
  1224.  */
  1225.  
  1226. ENTRY static void
  1227. CallBacksDone(spriteID)
  1228.     int spriteID;
  1229. {
  1230.     register Hash_Entry *hashPtr;
  1231.     register RecovHostState *hostPtr;
  1232.  
  1233.     LOCK_MONITOR;
  1234.  
  1235.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1236.     hostPtr = (RecovHostState *)hashPtr->value;
  1237.     hostPtr->state &= ~RECOV_REBOOT_CALLBACKS;
  1238.     if (hostPtr->state & (RECOV_FAILURE)) {
  1239.     /*
  1240.      * There has been a communication failure during the reboot callbacks.
  1241.      */
  1242.     hostPtr->numFailures++;
  1243.     hostPtr->state &= ~RECOV_FAILURE;
  1244.     hostPtr->state |= RECOV_WANT_RECOVERY;
  1245.     } else {
  1246.     hostPtr->numFailures = 0;
  1247.     }
  1248.     UNLOCK_MONITOR;
  1249.     return;
  1250. }
  1251.  
  1252. /*
  1253.  *----------------------------------------------------------------------
  1254.  *
  1255.  * CrashCallBacks --
  1256.  *
  1257.  *    Invoked asynchronously so that other modules
  1258.  *    can clean up behind the crashed host.  When done the host
  1259.  *    is marked as having recovery complete.  This unblocks server
  1260.  *    processes stalled in Recov_HostAlive.
  1261.  *
  1262.  * Results:
  1263.  *    None.
  1264.  *
  1265.  * Side effects:
  1266.  *    Invoke the crash call-backs.
  1267.  *    Clears the recovery in progress flag checked in Recov_HostAlive.
  1268.  *
  1269.  *----------------------------------------------------------------------
  1270.  */
  1271.  
  1272. static void
  1273. CrashCallBacks(data, callInfoPtr)
  1274.     ClientData data;
  1275.     Proc_CallInfo *callInfoPtr;
  1276. {
  1277.     register NotifyElement *notifyPtr;
  1278.     register int spriteID = (int)data;
  1279.  
  1280.     recov_Stats.crashes++;
  1281.     LIST_FORALL(&crashCallBackList, (List_Links *)notifyPtr) {
  1282.     if (notifyPtr->proc != (void (*)())NIL) {
  1283.         (*notifyPtr->proc)(spriteID, notifyPtr->data);
  1284.      }
  1285.     }
  1286.     MarkRecoveryComplete(spriteID);
  1287.     RECOV_TRACE(spriteID, RECOV_CRASH, RECOV_CUZ_DONE);
  1288.     callInfoPtr->interval = 0;    /* Don't call again */
  1289.     return;
  1290. }
  1291. #ifdef dying_state
  1292.  
  1293. /*
  1294.  *----------------------------------------------------------------------
  1295.  *
  1296.  * DelayedCrashCallBacks --
  1297.  *
  1298.  *    Invoked asynchronously from Recov_HostDead.  This is called after
  1299.  *    a grace period defined by recov_CrashDelay so that, for example,
  1300.  *    clients can be debugged without having the server close all
  1301.  *    their files.  When a client reboots, hoever, the crash callbacks
  1302.  *    will be sure to be called so other modules can clean up.
  1303.  *
  1304.  * Results:
  1305.  *    None.
  1306.  *
  1307.  * Side effects:
  1308.  *    Invoke the crash call-backs.
  1309.  *    Clears the recovery in progress flag checked in Recov_HostAlive.
  1310.  *
  1311.  *----------------------------------------------------------------------
  1312.  */
  1313.  
  1314. static void
  1315. DelayedCrashCallBacks(data, callInfoPtr)
  1316.     ClientData data;
  1317.     Proc_CallInfo *callInfoPtr;
  1318. {
  1319.     register NotifyElement *notifyPtr;
  1320.     register int spriteID = (int)data;
  1321.     int state;
  1322.  
  1323.     state = Recov_GetHostState(spriteID);
  1324.     if (state & RECOV_HOST_DYING) {
  1325.     RecovHostPrint(RECOV_PRINT_CRASH, spriteID,
  1326.         "crash call-backs being made\n");
  1327.     recov_Stats.crashes++;
  1328.     MarkHostDead(spriteID);
  1329.     LIST_FORALL(&crashCallBackList, (List_Links *)notifyPtr) {
  1330.         if (notifyPtr->proc != (void (*)())NIL) {
  1331.         (*notifyPtr->proc)(spriteID, notifyPtr->data);
  1332.          }
  1333.     }
  1334.     MarkRecoveryComplete(spriteID);
  1335.     } else if ((state & RECOV_HOST_DEAD) == 0) {
  1336.     recov_Stats.nonCrashes++;
  1337.     }
  1338.     callInfoPtr->interval = 0;    /* Don't call again */
  1339.     return;
  1340. }
  1341. #endif /* dying_state */
  1342.  
  1343. /*
  1344.  *----------------------------------------------------------------------
  1345.  *
  1346.  * MarkRecoveryComplete --
  1347.  *
  1348.  *    The recovery call-backs have completed, and this procedure's
  1349.  *    job is to mark that fact in the host hash table and to notify
  1350.  *    any processes that are blocked in Recov_HostAlive waiting for this.
  1351.  *
  1352.  * Results:
  1353.  *    None.
  1354.  *
  1355.  * Side effects:
  1356.  *    Sets the state, if any, in the host state table.
  1357.  *    Notifies the hostPtr->recovery condition
  1358.  *
  1359.  *----------------------------------------------------------------------
  1360.  */
  1361.  
  1362. ENTRY static void
  1363. MarkRecoveryComplete(spriteID)
  1364.     int    spriteID;
  1365. {
  1366.     register Hash_Entry *hashPtr;
  1367.     register RecovHostState *hostPtr;
  1368.  
  1369.     LOCK_MONITOR;
  1370.  
  1371.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1372.     if (hashPtr != (Hash_Entry *)NIL) {
  1373.     hostPtr = (RecovHostState *)hashPtr->value;
  1374.     if (hostPtr != (RecovHostState *)NIL) {
  1375.         hostPtr->state &= ~RECOV_CRASH_CALLBACKS;
  1376.         Sync_Broadcast(&hostPtr->recovery);
  1377.     }
  1378.     }
  1379.     UNLOCK_MONITOR;
  1380.     return;
  1381. }
  1382. #ifdef dying_state
  1383.  
  1384. /*
  1385.  *----------------------------------------------------------------------
  1386.  *
  1387.  * MarkHostDead --
  1388.  *
  1389.  *    Monitored procedure to change a host's state from dying to dead.
  1390.  *    This is done after the grace period has expired and we are
  1391.  *    about to call the crash callbacks.
  1392.  *
  1393.  * Results:
  1394.  *    None.
  1395.  *
  1396.  * Side effects:
  1397.  *    Set the state to RECOV_HOST_DEAD
  1398.  *
  1399.  *----------------------------------------------------------------------
  1400.  */
  1401.  
  1402. ENTRY static void
  1403. MarkHostDead(spriteID)
  1404.     int    spriteID;
  1405. {
  1406.     register Hash_Entry *hashPtr;
  1407.     register RecovHostState *hostPtr;
  1408.  
  1409.     LOCK_MONITOR;
  1410.  
  1411.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1412.     if (hashPtr != (Hash_Entry *)NIL) {
  1413.     hostPtr = (RecovHostState *)hashPtr->value;
  1414.     if (hostPtr != (RecovHostState *)NIL) {
  1415.         hostPtr->state &= ~RECOV_HOST_DYING;
  1416.         hostPtr->state |= RECOV_HOST_DEAD;
  1417.     }
  1418.     }
  1419.     UNLOCK_MONITOR;
  1420.     return;
  1421. }
  1422. #endif
  1423.  
  1424. /*
  1425.  *----------------------------------------------------------------------
  1426.  *
  1427.  * Recov_GetHostState --
  1428.  *
  1429.  *    This looks into    the host table to see and provides a guess
  1430.  *    as to the host's current state.  It uses a timestamp kept in
  1431.  *    the host state to see if there's been recent message traffic.
  1432.  *    If so, RECOV_HOST_ALIVE is returned.  If not, RECOV_STATE_UNKNOWN
  1433.  *    is returned and the caller should ping to make sure.  Finally,
  1434.  *    if it is known that the host is down already, then RECOV_HOST_DEAD
  1435.  *    is returned.
  1436.  *
  1437.  * Results:
  1438.  *    RECOV_STATE_UNKNOWN if the caller should ping to make sure.
  1439.  *    RECOV_HOST_ALIVE if the host is up (recent message traffic).
  1440.  *    RECOV_HOST_DEAD if the host is down (recent timeouts).
  1441.  *
  1442.  * Side effects:
  1443.  *    None.
  1444.  *
  1445.  *----------------------------------------------------------------------
  1446.  */
  1447.  
  1448. ENTRY int
  1449. Recov_GetHostState(spriteID)
  1450.     int spriteID;
  1451. {
  1452.     register Hash_Entry *hashPtr;
  1453.     register RecovHostState *hostPtr;
  1454.     register int state = RECOV_STATE_UNKNOWN;
  1455.     Time time;
  1456.  
  1457.     LOCK_MONITOR;
  1458.  
  1459.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1460.     if (hashPtr != (Hash_Entry *)NIL) {
  1461.     hostPtr = (RecovHostState *)hashPtr->value;
  1462.     if (hostPtr != (RecovHostState *)NIL) {
  1463.         state = hostPtr->state &
  1464.      (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING|RECOV_HOST_DYING|RECOV_HOST_DEAD);
  1465.         if (state & (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING)) {
  1466.         /*
  1467.          * Check for recent message traffic before admitting
  1468.          * that the other machine is up.
  1469.          */
  1470.         Timer_GetTimeOfDay(&time, (int *)NIL, (Boolean *)NIL);
  1471.         Time_Subtract(time, hostPtr->time, &time);
  1472.         if (Time_GT(time, time_TenSeconds)) {
  1473.             state = RECOV_STATE_UNKNOWN;
  1474.         }
  1475.         }
  1476.     }
  1477.     }
  1478.     UNLOCK_MONITOR;
  1479.     return(state);
  1480. }
  1481.  
  1482. /*
  1483.  *----------------------------------------------------------------------
  1484.  *
  1485.  * RecovGetLastHostState --
  1486.  *
  1487.  *    This looks into    the host table to pass back the
  1488.  *    host's current state.  It just uses whatever state the
  1489.  *    host has marked currently, and does no further interpretation.
  1490.  *
  1491.  * Results:
  1492.  *    hostPtr->state
  1493.  *
  1494.  * Side effects:
  1495.  *    None.
  1496.  *
  1497.  *----------------------------------------------------------------------
  1498.  */
  1499.  
  1500. ENTRY int
  1501. RecovGetLastHostState(spriteID)
  1502.     int spriteID;
  1503. {
  1504.     register Hash_Entry *hashPtr;
  1505.     register RecovHostState *hostPtr;
  1506.     register int state = RECOV_STATE_UNKNOWN;
  1507.  
  1508.     LOCK_MONITOR;
  1509.  
  1510.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1511.     if (hashPtr != (Hash_Entry *)NIL) {
  1512.     hostPtr = (RecovHostState *)hashPtr->value;
  1513.     if (hostPtr != (RecovHostState *)NIL) {
  1514.         state = hostPtr->state;
  1515.     }
  1516.     }
  1517.     UNLOCK_MONITOR;
  1518.     return(state);
  1519. }
  1520.  
  1521. /*
  1522.  *----------------------------------------------------------------------
  1523.  *
  1524.  * RecovCheckHost --
  1525.  *
  1526.  *    This decides if we should check up on a host.  If there has
  1527.  *    been recent message traffic there is no need to ping now,
  1528.  *    but we should check again later.  If there has been no
  1529.  *    message traffic our caller should ping.  Finally, if
  1530.  *    there are no reboot callbacks associated with the host,
  1531.  *    then we are not interested anymore.  Thus there are three
  1532.  *    values to return.
  1533.  *
  1534.  * Results:
  1535.  *    -1 if we are no longer interested in the host.
  1536.  *    0 if the host is presumably up and we don't have to ping.
  1537.  *    1 if our caller should ping.
  1538.  *
  1539.  * Side effects:
  1540.  *    None.
  1541.  *
  1542.  *----------------------------------------------------------------------
  1543.  */
  1544.  
  1545. ENTRY int
  1546. RecovCheckHost(spriteID)
  1547.     int    spriteID;
  1548. {
  1549.     register Hash_Entry *hashPtr;
  1550.     register RecovHostState *hostPtr = (RecovHostState *)NIL;
  1551.     register int check = -1;    /* forget about the host */
  1552.     register int state;
  1553.  
  1554.     LOCK_MONITOR;
  1555.  
  1556.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1557.     if (hashPtr != (Hash_Entry *)NIL) {
  1558.     hostPtr = (RecovHostState *)hashPtr->value;
  1559.     if ((hostPtr != (RecovHostState *)NIL) &&
  1560.         (!List_IsEmpty(&hostPtr->rebootList))) {
  1561.         state = hostPtr->state &
  1562.      (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING|RECOV_HOST_DYING|RECOV_HOST_DEAD);
  1563.         if (state & (RECOV_HOST_ALIVE|RECOV_HOST_BOOTING)) {
  1564.         /*
  1565.          * Check for recent message traffic before admitting
  1566.          * that the other machine is up.
  1567.          */
  1568.         Time time;
  1569.         Timer_GetTimeOfDay(&time, (int *)NIL, (Boolean *)NIL);
  1570.         Time_Subtract(time, hostPtr->time, &time);
  1571.         if (Time_GT(time, time_TenSeconds)) {
  1572.             check = 1;    /* ping the host now */
  1573.         } else {
  1574.             check = 0;    /* ping the host maybe next time */
  1575.         }
  1576.         } else if (state & (RECOV_HOST_DEAD|RECOV_HOST_DYING)) {
  1577.         check = 1;    /* ping the host now */
  1578.         }
  1579.     }
  1580.     }
  1581.     if (check < 0 && hostPtr != (RecovHostState *)NIL) {
  1582.     hostPtr->state &= ~RECOV_PINGING_HOST;
  1583.     }
  1584.     UNLOCK_MONITOR;
  1585.     return(check);
  1586. }
  1587.  
  1588. /*
  1589.  *----------------------------------------------------------------------
  1590.  *
  1591.  * Recov_GetStats --
  1592.  *
  1593.  *    Return the Recov_Stats to user-level, and perhaps more information
  1594.  *    about our internal opinion of other hosts.
  1595.  *
  1596.  * Results:
  1597.  *    None.
  1598.  *
  1599.  * Side effects:
  1600.  *    Copies data out to user-space.
  1601.  *
  1602.  *----------------------------------------------------------------------
  1603.  */
  1604. ReturnStatus
  1605. Recov_GetStats(size, userAddr)
  1606.     int size;
  1607.     Address userAddr;
  1608. {
  1609.     ReturnStatus status;
  1610.     int extraSpace = -1;
  1611.  
  1612.     if (size <= 0) {
  1613.     return(GEN_INVALID_ARG);
  1614.     }
  1615.     /*
  1616.      * See if the caller wants more than just statistics.
  1617.      */
  1618.     if (size > sizeof(Recov_Stats)) {
  1619.     extraSpace = size - sizeof(Recov_Stats);
  1620.     size = sizeof(Recov_Stats);
  1621.     }
  1622.     status = Vm_CopyOut(size, (Address)&recov_Stats, userAddr);
  1623.  
  1624. #ifdef notdef
  1625.     if (extraSpace > sizeof(int)) {
  1626.     /*
  1627.      * Fill the user-space buffer with a count of hosts,
  1628.      * and then information about each host.
  1629.      */
  1630.     userAddr += sizeof(Recov_Stats);
  1631.     status = Recov_DumpState(extraSpace, userAddr);
  1632.     }
  1633. #endif notdef
  1634.     return(status);
  1635. }
  1636.  
  1637. /*
  1638.  *----------------------------------------------------------------------
  1639.  *
  1640.  * Recov_DumpState --
  1641.  *
  1642.  *    Dump internal state to user-level.
  1643.  *
  1644.  * Results:
  1645.  *    None.
  1646.  *
  1647.  * Side effects:
  1648.  *    Copies data out to user-space.
  1649.  *
  1650.  *----------------------------------------------------------------------
  1651.  */
  1652. ReturnStatus
  1653. Recov_DumpState(size, userAddr)
  1654.     int size;
  1655.     Address userAddr;
  1656. {
  1657.     ReturnStatus status = SUCCESS;
  1658.     int numHosts, maxHosts;
  1659.     int *countPtr;
  1660.     int spriteID;
  1661.     Recov_State recovState;
  1662.  
  1663.     /*
  1664.      * We return a count, plus count number of Recov_State structures.
  1665.      */
  1666.     maxHosts = (size - sizeof(int)) / sizeof(Recov_State);
  1667.     countPtr = (int *)userAddr;
  1668.     if ((maxHosts == 0) && (size > sizeof(int))) {
  1669.     status = Vm_CopyOut(sizeof(int), (Address)&maxHosts, (Address)countPtr);
  1670.     return(status);
  1671.     }
  1672.      userAddr += sizeof(int);
  1673.     /*
  1674.      * Brute force.  Run through til MAX_HOSTS and try to grab
  1675.      * the state from the hash table.
  1676.      */
  1677.     numHosts = 0;
  1678.     for (spriteID = 1 ; spriteID < NET_NUM_SPRITE_HOSTS ; spriteID++) {
  1679.     if (Recov_GetHostInfo(spriteID, &recovState)) {
  1680.         status = Vm_CopyOut(sizeof(recovState), (Address)&recovState,
  1681.                 userAddr);
  1682.         if (status != SUCCESS) {
  1683.         return(status);
  1684.         }
  1685.         userAddr += sizeof(recovState);
  1686.         numHosts++;
  1687.         if (numHosts >= maxHosts) {
  1688.         break;
  1689.         }
  1690.     }
  1691.     }
  1692.  
  1693.     return(status);
  1694. }
  1695.  
  1696. /*
  1697.  *----------------------------------------------------------------------
  1698.  *
  1699.  * Recov_GetHostInfo --
  1700.  *
  1701.  *    Get the internal state about a host.
  1702.  *
  1703.  * Results:
  1704.  *    Fills in a Recov_State structure and returns TRUE,
  1705.  *    otherwise, if we don't know about the host, returns FALSE
  1706.  *
  1707.  * Side effects:
  1708.  *    None.
  1709.  *
  1710.  *----------------------------------------------------------------------
  1711.  */
  1712.  
  1713. ENTRY Boolean
  1714. Recov_GetHostInfo(spriteID, recovStatePtr)
  1715.     int spriteID;
  1716.     Recov_State *recovStatePtr;
  1717. {
  1718.     Hash_Entry *hashPtr;
  1719.     RecovHostState *hostPtr;
  1720.     Boolean found = FALSE;
  1721.  
  1722.     LOCK_MONITOR;
  1723.  
  1724.     if (spriteID <= 0 || spriteID == rpc_SpriteID) {
  1725.     goto exit;
  1726.     } else {
  1727.     hashPtr = Hash_LookOnly(recovHashTable, (Address)spriteID);
  1728.     if (hashPtr == (Hash_Entry *)NULL || hashPtr->value == (Address)NIL) {
  1729.         goto exit;
  1730.     } else {
  1731.         hostPtr = (RecovHostState *)hashPtr->value;
  1732.     }
  1733.     recovStatePtr->spriteID = spriteID;
  1734.     recovStatePtr->state = hostPtr->state;
  1735.     recovStatePtr->clientState = hostPtr->clientState;
  1736.     recovStatePtr->bootID = hostPtr->bootID;
  1737.     recovStatePtr->time = hostPtr->time;
  1738.     found = TRUE;
  1739.     }
  1740. exit:
  1741.     UNLOCK_MONITOR;
  1742.     return(found);
  1743. }
  1744.  
  1745.  
  1746. /*
  1747.  *----------------------------------------------------------------------
  1748.  *
  1749.  * Recov_PrintTraceRecord --
  1750.  *
  1751.  *    Format and print the client data part of a recovery trace record.
  1752.  *
  1753.  * Results:
  1754.  *    None.
  1755.  *
  1756.  * Side effects:
  1757.  *    printf to the display.
  1758.  *
  1759.  *----------------------------------------------------------------------
  1760.  */
  1761. int
  1762. Recov_PrintTraceRecord(clientData, event, printHeaderFlag)
  1763.     ClientData clientData;    /* Client data in the trace record */
  1764.     int event;            /* Type, or event, from the trace record */
  1765.     Boolean printHeaderFlag;    /* If TRUE, a header line is printed */
  1766. {
  1767.     RecovTraceRecord *recPtr = (RecovTraceRecord *)clientData;
  1768.     char name[128];
  1769.     if (printHeaderFlag) {
  1770.     /*
  1771.      * Print column headers and a newline.
  1772.      */
  1773.     printf("%10s %10s %17s\n", "Host", "State", "Event ");
  1774.     }
  1775.     if (clientData != (ClientData)NIL) {
  1776.     Net_SpriteIDToName(recPtr->spriteID, 128, name);
  1777.     if (*name == '\0') {
  1778.         printf("%10d ", recPtr->spriteID);
  1779.     } else {
  1780.         printf("%10s ", name);
  1781.     }
  1782.     printf("%-8s", GetState(recPtr->state));
  1783.     printf("%3s", (recPtr->state & RECOV_CRASH_CALLBACKS) ?
  1784.                 " C " : "   ");
  1785.     printf("%3s", (recPtr->state & RECOV_PINGING_HOST) ?
  1786.                 " P " : "   ");
  1787.     printf("%3s", (recPtr->state & RECOV_REBOOT_CALLBACKS) ?
  1788.                 " R " : "   ");
  1789.     printf("%3s", (recPtr->state & RECOV_WANT_RECOVERY) ?
  1790.                 " W " : "   ");
  1791.     switch(event) {
  1792.         case RECOV_CUZ_WAIT:
  1793.         printf("waiting");
  1794.         break;
  1795.         case RECOV_CUZ_WAKEUP:
  1796.         printf("wakeup");
  1797.         break;
  1798.         case RECOV_CUZ_INIT:
  1799.         printf("init");
  1800.         break;
  1801.         case RECOV_CUZ_REBOOT:
  1802.         printf("reboot");
  1803.         break;
  1804.         case RECOV_CUZ_CRASH:
  1805.         printf("crash");
  1806.         break;
  1807.         case RECOV_CUZ_CRASH_UNDETECTED:
  1808.         printf("crash undetected");
  1809.         break;
  1810.         case RECOV_CUZ_DONE:
  1811.         printf("done");
  1812.         break;
  1813.         case RECOV_CUZ_PING_ASK:
  1814.         printf("ping (ask)");
  1815.         break;
  1816.         case RECOV_CUZ_PING_CHK:
  1817.         printf("ping (check)");
  1818.         break;
  1819.         case RECOV_TRACE_FS_STALE:
  1820.         printf("stale FS handle");
  1821.         break;
  1822.         default:
  1823.         printf("(%x)", event);
  1824.         break;
  1825.     }
  1826.     /* Our caller prints a newline */
  1827.     }
  1828.     return 0;
  1829. }
  1830.  
  1831. /*
  1832.  *----------------------------------------------------------------------
  1833.  *
  1834.  * Recov_PrintTrace --
  1835.  *
  1836.  *    Dump out the recovery trace.  Called via a console L1 keystroke.
  1837.  *
  1838.  * Results:
  1839.  *    None.
  1840.  *
  1841.  * Side effects:
  1842.  *    Prints to the console.
  1843.  *
  1844.  *----------------------------------------------------------------------
  1845.  */
  1846.  
  1847. void
  1848. Recov_PrintTrace(clientData)
  1849.     ClientData clientData;
  1850. {
  1851.     int numRecs = (int)clientData;
  1852.  
  1853.     if (numRecs <= 0 || numRecs > recovTraceLength) {
  1854.     numRecs = recovTraceLength;
  1855.     }
  1856.     printf("RECOVERY TRACE\n");
  1857.     (void)Trace_Print(recovTraceHdrPtr, numRecs, Recov_PrintTraceRecord);
  1858.     Recov_PrintState();
  1859.     RecovPrintPingList();
  1860.     return;
  1861. }
  1862.  
  1863. /*
  1864.  *----------------------------------------------------------------------
  1865.  *
  1866.  * Recov_PrintState --
  1867.  *
  1868.  *    Dump out the recovery state.  Called via a console L1 keystroke.
  1869.  *
  1870.  * Results:
  1871.  *    None.
  1872.  *
  1873.  * Side effects:
  1874.  *    Prints to the console.
  1875.  *
  1876.  *----------------------------------------------------------------------
  1877.  */
  1878.  
  1879. void
  1880. Recov_PrintState()
  1881. {
  1882.     Hash_Search            hashSearch;
  1883.     register Hash_Entry        *hashEntryPtr;
  1884.     register RecovHostState    *hostPtr;
  1885.     char            hostName[128];
  1886.     Time_Parts            timeParts;
  1887.     Time            bootTime;
  1888.     int                localOffset; /* minute offset for our tz */
  1889.     Time            currentTime;
  1890.  
  1891.     printf("RECOVERY STATE\n");
  1892.     Hash_StartSearch(&hashSearch);
  1893.     for (hashEntryPtr = Hash_Next(recovHashTable, &hashSearch);
  1894.      hashEntryPtr != (Hash_Entry *)NIL;
  1895.      hashEntryPtr = Hash_Next(recovHashTable, &hashSearch)) {
  1896.     hostPtr = (RecovHostState *)hashEntryPtr->value;
  1897.     if (hostPtr != (RecovHostState *)NIL) {
  1898.  
  1899.         Net_SpriteIDToName(hostPtr->spriteID, 128, hostName);
  1900.         printf("%-14s %-8s", hostName, GetState(hostPtr->state));
  1901.         printf(" bootID 0x%8x", hostPtr->bootID);
  1902.  
  1903.         /*
  1904.          * Print out boot time in our timezone.
  1905.          */
  1906.         Timer_GetTimeOfDay(¤tTime, &localOffset, (Boolean *) NIL);
  1907.         bootTime.seconds = hostPtr->bootID;
  1908.         bootTime.microseconds = 0;
  1909.         bootTime.seconds += (localOffset * 60);
  1910.         Time_ToParts(bootTime.seconds, FALSE, &timeParts);
  1911.         timeParts.month++;    /* So Jan is 1, not 0 */
  1912.         printf(" %d/%d/%d %d:%02d:%02d ", timeParts.month,
  1913.             timeParts.dayOfMonth,
  1914.             timeParts.year, timeParts.hours, timeParts.minutes,
  1915.             timeParts.seconds);
  1916.  
  1917.         /*
  1918.          * Print seconds ago we last heard from host.
  1919.          */
  1920.         printf("    %d ", currentTime.seconds - hostPtr->time.seconds);
  1921.         PrintExtraState(hostPtr);
  1922.         printf("\n");
  1923.     }
  1924.     }
  1925.     return;
  1926. }
  1927.  
  1928. /*
  1929.  *----------------------------------------------------------------------
  1930.  *
  1931.  * GetState --
  1932.  *
  1933.  *    Return a printable string for the host's state.
  1934.  *
  1935.  * Results:
  1936.  *    A pointer to a string.
  1937.  *
  1938.  * Side effects:
  1939.  *    None.
  1940.  *
  1941.  *----------------------------------------------------------------------
  1942.  */
  1943.  
  1944. static char *
  1945. GetState(state)
  1946.     int state;
  1947. {
  1948.     switch(state & (RECOV_HOST_ALIVE|RECOV_HOST_DYING|RECOV_HOST_DEAD|
  1949.             RECOV_HOST_BOOTING)) {
  1950.     default:
  1951.     case RECOV_STATE_UNKNOWN:
  1952.         return("Unknown");
  1953.     case RECOV_HOST_ALIVE:
  1954.         return("Alive");
  1955.     case RECOV_HOST_BOOTING:
  1956.         return("Booting");
  1957.     case RECOV_HOST_DYING:
  1958.         return("Dying");
  1959.     case RECOV_HOST_DEAD:
  1960.         return("Dead");
  1961.     }
  1962. }
  1963.  
  1964. /*
  1965.  *----------------------------------------------------------------------
  1966.  *
  1967.  * RecovExtraState --
  1968.  *
  1969.  *    Prints out strings for various auxilliary state bits.
  1970.  *
  1971.  * Results:
  1972.  *    None.
  1973.  *
  1974.  * Side effects:
  1975.  *    Prints out stuff.
  1976.  *
  1977.  *----------------------------------------------------------------------
  1978.  */
  1979.  
  1980. static void
  1981. PrintExtraState(hostPtr)
  1982.     RecovHostState *hostPtr;
  1983. {
  1984.     if (hostPtr->state & RECOV_CRASH_CALLBACKS) {
  1985.     printf("Crash callbacks ");
  1986.     }
  1987.     if (hostPtr->state & RECOV_WANT_RECOVERY) {
  1988.     printf("Want recovery ");
  1989.     }
  1990.     if (hostPtr->state & RECOV_REBOOT_CALLBACKS) {
  1991.     printf("Reboot callbacks ");
  1992.     }
  1993.     if (hostPtr->state & RECOV_FAILURE) {
  1994.     printf("Failure ");
  1995.     }
  1996.     if (hostPtr->clientState & CLT_RECOV_IN_PROGRESS) {
  1997.     printf("Clt-inprogress ");
  1998.     }
  1999.     if (hostPtr->clientState & SRV_RECOV_IN_PROGRESS) {
  2000.     printf("Srv-inprogress ");
  2001.     }
  2002. }
  2003.  
  2004.  
  2005. void
  2006. Recov_ChangePrintLevel(newLevel)
  2007.     int    newLevel;
  2008. {
  2009.     recov_PrintLevel = newLevel;
  2010.     return;
  2011. }
  2012.